﻿namespace  EFS.Common.UI.Shared
{
	public class CheckBoxList : System.Windows.Controls.UserControl
	{
		#region Composition

		/// <summary>
		/// local mapping
		/// </summary>
		private System.Collections.Generic.Dictionary<System.Windows.Controls.CheckBox, System.Object> mapping = 
			new System.Collections.Generic.Dictionary<System.Windows.Controls.CheckBox, System.Object>();

		#endregion

		#region delegates

		/// <summary>
		/// Checked delegate
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		public delegate void Checked(System.Object[] userData);

		/// <summary>
		/// Checked registrar
		/// </summary>
		public Checked OnChecked;

		/// <summary>
		/// UnChecked delegate
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		public delegate void UnChecked(System.Object[] userData);

		/// <summary>
		/// Checked registrar
		/// </summary>
		public UnChecked OnUnChecked;

		#endregion

		#region Locals
		/// groupName
		private System.String groupName = System.Guid.NewGuid().ToString();

		/// itemsPadding
		private System.Double itemsMargin = 3;

		/// stack panel
		private System.Windows.Controls.StackPanel stackPanel = new System.Windows.Controls.StackPanel();

		#endregion

		#region Constructors
		/// Implicit
		public CheckBoxList()
		{
			// set defaults
			ItemsMargin = 2;

			// init stack panel
			stackPanel.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
			stackPanel.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
			stackPanel.Orientation = System.Windows.Controls.Orientation.Vertical;

			// set content
			Content = stackPanel;

			// only if in design tool
#if SILVERLIGHT
			if (System.ComponentModel.DesignerProperties.IsInDesignTool)
#else
			if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
#endif
			{
				Add("1", "Check Box 1");
				Add("2", "Check Box 2");
			}
		}
		#endregion

		#region Properties
		/// Property GroupName: Get
		public System.String GroupName
		{
			get
			{
				return groupName;
			}
		}

		/// Property ItemsMargin: Get, Set
		public System.Double ItemsMargin
		{
			get
			{
				return itemsMargin;
			}
			set
			{
				itemsMargin = value;
				foreach(System.Windows.Controls.CheckBox checkBox in mapping.Keys)
				{
					checkBox.Margin = ItemsInternalComputedMargin;
				}
			}
		}

		/// Property ItemsInternalComputedMarginItemsMargin: Get
		private System.Windows.Thickness ItemsInternalComputedMargin
		{
			get
			{
				return new System.Windows.Thickness(0, itemsMargin, 0, itemsMargin);
			}
		}

		/// Property ItemsCount: Get
		public System.Int32 ItemsCount
		{
			get
			{
				return mapping.Values.Count;
			}
		}

		/// Property SelectedItem: Get
		public System.Object[] SelectedValues
		{
			get
			{
				// make list
				System.Collections.Generic.List<System.Object> selectedItems = new System.Collections.Generic.List<System.Object>();
				
				// manage all
				foreach (System.Windows.Controls.CheckBox checkBox in mapping.Keys)
				{
					// test selected
					if (checkBox.IsChecked.HasValue && checkBox.IsChecked.Value)
					{
						selectedItems.Add(mapping[checkBox]);
					}
				}

				// none
				return selectedItems.ToArray();
			}
		}

		#endregion

		#region Utilities
		/// VerifyIndexRange
		private void VerifyIndexRange(System.Int32 index)
		{
			// check
			EFS.Common.Verify.Condition(index >= 0 && index < ItemsCount, "Index out of bounds");
		}

		#endregion

		#region Handle list

		/// <summary>
		/// Add to list
		/// </summary>
		/// <param name="userData"></param>
		/// <param name="label"></param>
		/// <param name="selected"></param>
		public void Add(System.Object userData, System.String label, System.Boolean selected = false)
		{
			// check
			EFS.Common.Verify.String(label, "label");

			// create new
			System.Windows.Controls.CheckBox checkBox = new System.Windows.Controls.CheckBox();
			checkBox.VerticalAlignment = System.Windows.VerticalAlignment.Center;
			checkBox.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
			checkBox.IsChecked = selected;
			checkBox.Content = label;
			checkBox.Margin = ItemsInternalComputedMargin;
			checkBox.Checked += checkBox_Checked;
			checkBox.Unchecked += checkBox_Unchecked;

			// add to lists
			mapping.Add(checkBox, userData);

			// add to stack panel
			stackPanel.Children.Add(checkBox);
		}

		/// Clear
		public void Clear()
		{
			// remove from lists
			mapping.Clear();

			// remove from stack panel
			stackPanel.Children.Clear();
		}

		/// Select All
		public void SelectAll(System.Boolean notifyOnce)
		{
			// remove delegates
			if (notifyOnce)
			{
				// clear check events
				RemoveCheckEventHandlers();
			}

			// cicle all
			System.Collections.Generic.List<System.Object> userDataList = new System.Collections.Generic.List<System.Object>();
			foreach (System.Windows.Controls.CheckBox checkBox in mapping.Keys)
			{
				if (!EFS.Common.UI.Misc.Ischecked(checkBox))
				{
					// set checked
					checkBox.IsChecked = true;

					// add to notify
					if (notifyOnce)
					{
						// add mapping
						userDataList.Add(mapping[checkBox]);
					}
				}
			}

			// notify and put beck delegates
			if (notifyOnce)
			{
				// notify
				OnChecked(userDataList.ToArray());

				// add back check events handlers
				AddCheckEventHandlers();
			}
		}

		/// ClearSelection
		public void ClearSelection(System.Boolean notifyOnce)
		{
			// remove delegates
			if (notifyOnce)
			{
				// clear check events
				RemoveCheckEventHandlers();
			}

			// cicle all
			System.Collections.Generic.List<System.Object> userDataList = new System.Collections.Generic.List<System.Object>();
			foreach (System.Windows.Controls.CheckBox checkBox in mapping.Keys)
			{
				if (EFS.Common.UI.Misc.Ischecked(checkBox))
				{
					// set unchecked
					checkBox.IsChecked = false;

					// add to notify
					if (notifyOnce)
					{
						// add mapping
						userDataList.Add(mapping[checkBox]);
					}
				}
			}

			// notify and put beck delegates
			if (notifyOnce)
			{
				// notify
				OnUnChecked(userDataList.ToArray());

				// add back check events handlers
				AddCheckEventHandlers();
			}
		}
		#endregion

		#region Internals

		/// RemoveCheckEventHandlers
		public void RemoveCheckEventHandlers()
		{
			// cicle all
			foreach (System.Windows.Controls.CheckBox checkBox in mapping.Keys)
			{
				checkBox.Checked -= checkBox_Checked;
				checkBox.Unchecked -= checkBox_Unchecked;
			}
		}

		/// AddCheckEventHandlers
		public void AddCheckEventHandlers()
		{
			// cicle all
			foreach (System.Windows.Controls.CheckBox checkBox in mapping.Keys)
			{
				checkBox.Checked += checkBox_Checked;
				checkBox.Unchecked += checkBox_Unchecked;
			}
		}

		#endregion

		#region Events
		/// checkBox_Checked
		private void checkBox_Checked(object sender, System.Windows.RoutedEventArgs e)
		{
			if (null != OnChecked)
			{
				OnChecked(new System.Object[] {mapping[sender as System.Windows.Controls.CheckBox]});
			}
		}

		/// checkBox_Unchecked
		private void checkBox_Unchecked(object sender, System.Windows.RoutedEventArgs e)
		{
			if (null != OnChecked)
			{
				OnChecked(new System.Object[] { mapping[sender as System.Windows.Controls.CheckBox] });
			}
		}
		#endregion
	}

}